# encoding: utf-8

from Bfee import Bfee
from get_scale_csi import GetScaleCsi
import json
import matplotlib.pyplot as plt
import math
import numpy as np
import scipy.signal as signal
import sys


if __name__ == '__main__':

    '''
    服务器上的路径：
    # get argv and get filepath on server
    '''
    fileName = sys.argv[1]
    user = sys.argv[2]
    tempChar = fileName[0]
    actType = 'run'
    if tempChar == 'r':
        actType = 'run'
    elif tempChar == 'w':
        actType = 'walk'
    elif tempChar == 's':
        actType = 'shake'

    # path of file to save
    '''
    path of upload .dat file
    path of origin amplitude array
    path of origin phase array
    path of dealt amplitude array
    path of dealt phase array
    path of abnormal dealt array
    '''


    upload = '../data/' + user + '/upload/' + actType + '/' + fileName + '.dat'
    originAmpPath = '../data/' + user + '/origin/' + actType + '/amp/'
    originPhasePath = '../data/' + user + '/origin/' + actType + '/phase/'
    dealtAmpPath = '../data/' + user + '/dealt/' + actType + '/amp/'
    dealtPhasePath = '../data/' + user + '/dealt/' + actType + '/phase/'
    abnormalPath = '../data/' + user + '/dealt/' + actType + '/abnormal/'


    # initial
    bfee = Bfee.FromFile(upload, model_name_encode="gb2312")
    csiLength = len(bfee.allCsi)  # CSI包的个数
    csiLine = 1
    samplePacket = 100
    # package num of csi
    PI = math.pi
    distance=20
    listTemp = [complex(0, 0) for index in range(csiLength)]
    dataGet = np.array([listTemp for index in range(30)])

    '''
     这里传输协议为802.11n
     带宽为20kHz
     子载波数量为30
     csiSignal数组为上述情况下的子载波编号
    '''
    csiSignal = [-28, -26, -24, -22, -20, -18, -16, -14, -12, -10, -8, -6, -4, -2,
                 -1, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 28]
    '''
    amp array, phase array, dealt amp array, dealt phase array
    幅度、相位、去噪后幅度、去噪后相位
    '''
    listTemp = [0.0 for index in range(csiLength)]
    # 幅度原始矩阵
    amp = np.array([listTemp for index in range(30)])
    # 相位原始矩阵
    phase = np.array([listTemp for index in range(30)])
    # 幅度去噪矩阵
    ampDealt = np.array([listTemp for index in range(30)])
    # 相位去噪矩阵
    phaseDealt = np.array([listTemp for index in range(30)])

    # 异常算法2,3的矩阵说明
    # abnormal array
    abnormal3 = np.array([0.0 for index in range(csiLength)])
    # E of abnormal point in the left
    abnormalLeft = np.array([0.0 for index in range(csiLength)])
    # E of abnormal point in the right
    abnormalRight = np.array([0.0 for index in range(csiLength)])
    # variance of abnormal point in the left
    abnormalLeftVariance = np.array([0.0 for index in range(csiLength)])
    # variance of abnormal point in the right
    abnormalRightVariance = np.array([0.0 for index in range(csiLength)])
    # variance of abnormal point
    abnormalVariance = np.array([0.0 for index in range(csiLength)])
    # time abnormal
    abnormalTime = np.array([0 for index in range(csiLength // samplePacket + 1)])

    seconds=0
    butterN=2
    butterWn=0.02
    stepLength = 100
    if(csiLength<100):
        stepLength =3
        butterWn=0.2


    '''
    take csi data
    调用GetScaledCsi得到原始的从.dat文件中提取出来的动作数据（三维复数矩阵）
    将其降维得到dataGet（二维复数矩阵）
    '''
    for jTemp in range(0, csiLength):
        csiMatric = GetScaleCsi(bfee.dicts[jTemp])
        # csiMatrix: 3-d complex128
        for iTemp in range(30):
            dataGet[iTemp][jTemp] = csiMatric[iTemp, 0, 0]
            # dataGet: 2-d complex128

    '''
    幅度去噪：
    get amp,phase,dealt_amp from origin data
    从二维复数矩阵dataGet中提取原始幅度和原始相位矩阵 
    '''
    for iTemp in range(csiLength):
        for jTemp in range(30):
            # 从CSI矩阵中获取原始幅度和原始相位矩阵
            amp[jTemp][iTemp] = abs(dataGet[jTemp][iTemp])
            phase[jTemp][iTemp] = np.angle(dataGet[jTemp][iTemp])

            # 对得到的原始幅度利用巴特沃斯低通滤波器进行滤波
            bTemp, aTemp = signal.butter(butterN, butterWn, 'low')
            ampDealt = signal.filtfilt(bTemp, aTemp, amp)

    '''
    相位转换：
    利用上述csiSignal数组，利用该模式下子载波对称性，对相位进行线性转换。
    在很大程度除掉原始相位信息中的随机相位补偿。
    '''
    tempArray = np.array([listTemp for index in range(30)])
    for iTemp in range(csiLength):
        tempDiff = 0
        tempArray[0][iTemp] = phase[0][iTemp]
        for jTemp in range(1, 30):
            tempAns = phase[jTemp][iTemp] - phase[jTemp - 1][iTemp]
            # 相位取值，如果大于一个周期，需要减去这个周期，确保当前相位在[-PI,PI]之间
            if tempAns > PI:
                tempDiff = tempDiff + 1
            tempArray[jTemp][iTemp] = phase[jTemp][iTemp] - tempDiff * PI * 2

    sumMatrix = np.array([0.0 for iTemp in range(csiLength)])
    for iTemp in range(csiLength):
        for jTemp in range(30):
            sumMatrix[iTemp] += tempArray[jTemp][iTemp]

    for iTemp in range(csiLength):
        tempAns = (tempArray[29][iTemp] - tempArray[0][iTemp]) / (csiSignal[29] - csiSignal[0])
        tempSignal = sumMatrix[iTemp] / 30
        for jTemp in range(30):
            phaseDealt[jTemp][iTemp] = tempArray[jTemp][iTemp] - tempAns * csiSignal[jTemp] - tempSignal


    '''
    异常处理算法3：
    step1： 首先检测并去除异常点
    step2： 按照设定的步长遍历整个整条流，求出在步长范围内的最大值和最小值
             计算出最大值和最小值的差值，将差值看做整个步长范围内的波动
    step3： 计算出波动的平均值，每个范围内都与平均值进行比较
            如果高于平均值，波动视为较大，则此时将原值保持不动
            如果低于平均值，波动视为较小，则此时将矩阵置为0
    step4： 最后排除一段范围内一直递增和递减的情况
    '''

    # 检测异常点并去除
    '''
    这里amp_copy数组为amp的副本，主要利用这个副本来剔除部分异常值
    根据常理，我们知道运动状态不应该突变，因此当某一点过高或者过低的时候，可以判断它为异常（这里指数据收集存在问题)
    '''
    amp_copy = amp
    for i in range(csiLength - 1):
        if i != 0:
            csiTemp = amp_copy[csiLine][i + 1] - amp_copy[csiLine][i - 1] - 1 / 3 * amp_copy[csiLine][i]
            if csiTemp > 0:
                amp_copy[csiLine][i] = (amp_copy[csiLine][i + 1] + amp_copy[csiLine][i - 1]) / 2

    # 计算一定范围内的最大值和最小值的差距，来计算波动大小
    '''
    这部分设置stepLength为步长，按照这个步长遍历整个二维矩阵，求出在步长范围内的最大值和最小值
    计算出最大值和最小值的差值，将差值看做整个步长范围内的波动
    计算出波动的平均值，每个范围内都与平均值进行比较
    如果高于平均值，波动视为较大，则此时将原值保持不动
    如果低于平均值，波动视为较小，则此时将矩阵置为0
    '''
    abnormalMax = np.array([0.0 for i in range((csiLength // stepLength) + 1)])
    abnormalMin = np.array([0.0 for i in range((csiLength // stepLength) + 1)])
    abnormalMinus = np.array([0.0 for i in range((csiLength // stepLength) + 1)])
    abnormalV = np.array([0.0 for index in range((csiLength // stepLength) + 1)])
    abnormalFlag = np.array([0 for i in range((csiLength // stepLength) + 1)])
    for index in range((csiLength // stepLength)):
        i = index * stepLength
        abnormalMax[index] = np.max(amp_copy[csiLine][i:i + stepLength])
        abnormalMin[index] = np.min(amp_copy[csiLine][i:i + stepLength])
        abnormalMinus[index] = np.abs(abnormalMax[index] - abnormalMin[index])

    limit = np.mean(abnormalMinus)
    for index in range((csiLength // stepLength)):
        i = index * stepLength
        for j in range(stepLength):
            if abnormalMinus[index] > limit:
                if i + j < csiLength:
                    abnormal3[i + j] = amp_copy[csiLine][i + j]
                    abnormalFlag[index]=1
            else:
                if i + j < csiLength:
                    abnormal3[i + j] = 0
                    abnormalFlag[index] = 0

    seconds = csiLength // stepLength
    if(csiLength<=100):
        range1=3
    else:
        range1 = 70

    if(csiLength>100):
        flag = np.array([0.0 for i in range((csiLength // stepLength) + 1)])
        for index in range((csiLength // stepLength)):
            i = index * stepLength
            for j in range(stepLength):
                if i + j < csiLength - 1:
                    if amp[csiLine][i + j + 1] > amp[csiLine][i + j]:
                        flag[index] += 1
                    else:
                        flag[index] = 0

            # 到这里，排除直线上升和直线下降的情况。
            for k in range(stepLength):
                if i + k < csiLength - 1:
                    if amp[csiLine][i + k + 1] < amp[csiLine][i + k]:
                        flag[index] += 1  # 你不行啊
                    else:
                        flag[index] = 0
            if flag[index] >= range1:
                for j in range(stepLength):
                    if i + j < csiLength:
                        abnormal3[i + j] = 0

    num=0;
    for index in range(csiLength // stepLength):
        if(abnormalFlag[index]==1):
            num+=1;

    for index in range(csiLength // stepLength):
        i = index * stepLength+1
        if(abnormal3[i]==0):
            abnormalV[index]=0
        else:
            abnormalV[index]=round(distance/num,2)


    '''
    保存为json文件：
    将json文件保存到服务器中，前端通过该json文件绘制对应曲线图
    原始幅度：
    原始相位：
    巴特沃斯滤波去噪后幅度
    高斯低通滤波去噪后幅度
    相位线性转换后相位
    异常处理结果矩阵1
    异常处理结果矩阵2
    异常处理结果矩阵3
    '''
    if (dataGet.any() == False):
        raise ValueError
    else:
        amp = amp.tolist()
        phase = phase.tolist()

        # save amplitude and phase json file
        originAmpName = originAmpPath + fileName + '_amp.json'  # 原始Amp保存名
        saveJsonFilePath = open(originAmpName, 'w')
        saveJsonArray = json.dump(amp, saveJsonFilePath)

        originPhaseName = originPhasePath + fileName + '_phase.json'  # 原始Phase保存名
        saveJsonFilePath = open(originPhaseName, 'w')
        saveJsonArray = json.dump(phase, saveJsonFilePath)

        ampDealt = ampDealt.tolist()
        phaseDealt = phaseDealt.tolist()

        dealtampName = dealtAmpPath + 'dealt_' + fileName + '_amp.json'  # 处理后Phase保存名
        saveJsonFilePath = open(dealtampName, 'w')
        saveJsonArray = json.dump(ampDealt, saveJsonFilePath)

        dealtPhaseName = dealtPhasePath + 'dealt_' + fileName + '_phase.json'  # 处理后Phase保存名
        saveJsonFilePath = open(dealtPhaseName, 'w')
        saveJsonArray = json.dump(phaseDealt, saveJsonFilePath)

        abnormal3 = abnormal3.tolist()
        abnormal3 = [abnormal3 for i in range(1)]
        abnormalV = abnormalV.tolist()

        # save abnormal dealt json file
        abnormalName = abnormalPath + 'abnormal_' + fileName + '.json'  # 处理后Amp保存名
        saveJsonFilePath = open(abnormalName, 'w')
        saveJsonArray = json.dump(abnormal3, saveJsonFilePath)

        # save abnormal v json file
        abnormalName = abnormalPath + 'abnormal_' + fileName + '_v.json'  # 处理后Amp保存名
        saveJsonFilePath = open(abnormalName, 'w')
        saveJsonArray = json.dump(abnormalV, saveJsonFilePath)


